package com.woniu.service.impl;

import com.woniu.dto.CreatePrescriptionRequestDTO;
import com.woniu.dto.PrescriptionItemDTO;
import com.woniu.entity.*;
import com.woniu.mapper.*;
import com.woniu.service.DrugPrescriptionService;
import com.woniu.utils.ResponseEnum;
import com.woniu.utils.ResponseUtil;
import com.woniu.utils.SnowflakeIdGenerator;
import com.woniu.utils.UserContext;
import com.woniu.vo.DrugDistributionVO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class DrugPrescriptionServiceImpl implements DrugPrescriptionService {
    @Resource
    private DrugMapper drugMapper;
    @Resource
    private DrugDistributionMapper drugDistributionMapper;
    @Resource
    private MedicineDetailMapper medicineDetailMapper;
    @Resource
    private InpatientRecordMapper inpatientRecordMapper;
    @Resource
    private MedicineFeeDetailMapper medicineFeeDetailMapper;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseUtil createPrescription(CreatePrescriptionRequestDTO request) throws ParseException, InterruptedException {
        //获取医生id
        Integer currentDoctorId = UserContext.ContextUserId();
        //设置总金额为0
        BigDecimal totalPrice = BigDecimal.ZERO;

        List<MedicineDetail> detailsToInsert = new ArrayList<>();

        // 校验库存、计算总价
        for (PrescriptionItemDTO item : request.getItems()) {
            Drug drug = drugMapper.findDrugForPrescription(item.getDrugId()); //

            if (drug == null) {
                return ResponseUtil.get(ResponseEnum.FAIL, "开药失败：未找到ID为 " + item.getDrugId() + " 的药品");
            }
            if (drug.getDsStock() < item.getQuantity()) {
                return ResponseUtil.get(ResponseEnum.DRUG_STOCK_NOT_ENOUGH, "库存不足：" + drug.getDsName());
            }

            // 累计总价
            BigDecimal itemTotal = drug.getDsOutprice().multiply(new BigDecimal(item.getQuantity()));
            totalPrice = totalPrice.add(itemTotal);

            // 准备用药明细对象
            MedicineDetail detail = new MedicineDetail();
            detail.setMdDrugstoreid(drug.getId());
            detail.setMdName(drug.getDsName());
            detail.setMdNum(item.getQuantity());
            detail.setMdBuyprice(drug.getDsOutprice());
            detailsToInsert.add(detail);
        }

        // 如果是住院病人，立即扣除押金
        if ("1".equals(request.getType())) {
            // 2.1 检查押金是否充足
            InpatientRecord record = inpatientRecordMapper.findActiveRecordByPatientId(request.getPatientId());
            if (record == null) {
                return ResponseUtil.get(ResponseEnum.FAIL, "扣费失败：未找到患者的在院记录");
            }
            if (record.getHzBalance().compareTo(totalPrice) < 0) {
                String msg = String.format("押金不足，开药失败！(当前余额: %.2f元, 本次药费: %.2f元)",
                        record.getHzBalance().doubleValue(),
                        totalPrice.doubleValue());
                return ResponseUtil.get(ResponseEnum.FAIL, msg);
            }

            // 2.2 尝试扣费
            int feeRows = inpatientRecordMapper.deductBalance(request.getPatientId(), totalPrice); //
            if (feeRows == 0) {
                // 扣费失败 (并发或余额不足)
                return ResponseUtil.get(ResponseEnum.FAIL, "押金扣除失败，请重试");
            }
        }

        // 步骤 3: (保留) 扣减药品库存
        for (PrescriptionItemDTO item : request.getItems()) {
            Integer rowsAffected = drugMapper.decreaseStock(item.getDrugId(), item.getQuantity()); //
            if (rowsAffected == 0) {
                // 如果扣费成功，但扣库存失败，事务将回滚 (押金也会退回)
                throw new RuntimeException("库存扣减失败（并发导致），操作已回滚");
            }
        }

        SnowflakeIdGenerator sfg = new SnowflakeIdGenerator();
        String s = String.valueOf(sfg.nextId());

        // 步骤 4: 创建药品发放总单
        DrugDistribution distribution = new DrugDistribution();
        distribution.setPpCaseid(request.getPatientId());
        distribution.setPpWorkerid(currentDoctorId);
        distribution.setPpDate(new Date());

        // (修改) 设置状态
        if ("1".equals(request.getType())) {
            // 住院病人：已扣费、已扣库存，等待药房发药
            distribution.setPpStatus("1"); // 1 = 待发药 (或 "0"=未取药，取决于您药房的流程)
            // 我们使用 "0" (未取药)，与您原文件 保持一致
            distribution.setPpStatus("0"); // 0 = 未取药
        } else {
            // 门诊病人：未扣费、已扣库存，等待缴费
            distribution.setPpStatus("0"); // 0 = 未缴费/未取药
        }

        distribution.setPpType(request.getType());
        distribution.setTotalprice(totalPrice);
        distribution.setPpNo(s);

        drugDistributionMapper.insertSelective(distribution); //
        Integer prescriptionId = distribution.getId();


        // 步骤 5: (新增) 如果是住院病人，记录药品费用流水
        if ("1".equals(request.getType())) {
            MedicineFeeDetail fee = new MedicineFeeDetail();
            fee.setMfMedicationid(prescriptionId); // 关联到处方单ID
            fee.setMfPrice(totalPrice);
            fee.setMfDate(new Date());
            fee.setMfCaseid(request.getPatientId());
            fee.setMfNo("YP-" + s); // 使用雪花ID作为流水号
            medicineFeeDetailMapper.insertSelective(fee); //
        }

        // 步骤 6: 批量插入用药明细
        for (MedicineDetail detail : detailsToInsert) {
            detail.setMdPrescriptionid(prescriptionId);
            medicineDetailMapper.insertSelective(detail); //
        }

        String successMsg = "1".equals(request.getType()) ? "开药成功 (已扣除押金)" : "开药成功 (门诊)";
        return ResponseUtil.get(ResponseEnum.OK, successMsg);
    }
    @Override
    public ResponseUtil getPrescriptionHistory(Integer patientId) {
        List<DrugDistributionVO> prescriptions
                = drugDistributionMapper.findPrescriptionsByPatientId(patientId);
        return prescriptions != null ?
                ResponseUtil.get(ResponseEnum.OK, prescriptions)
                : ResponseUtil.get(ResponseEnum.FAIL);
    }

}
